<?php

namespace app\merchants\services;

use app\common\loader\ModelMerchant;
use app\common\loader\ModelShop;
use app\common\loader\ModelVirtual;
use app\common\loader\Services;
use think\db\exception\DbException;
use think\Exception;

/**
 * 虚码管理
 */
class VirtualService
{

    /**
     * 虚码规则列表
     * @param array $options
     * @return array
     * @throws Exception
     */
    public function getPromoPage(array $options): array
    {
        if (empty($options['field'])) {
            $options['field'] = 'id,mer_id,title,product_type,limit_num,scanned_num,status,begin_time,end_time,update_at';
        }
        // 获取列表列表
        $options['without_field'] = ['union_rule'];
        $options['order'] = 'id desc';
        $list = ModelVirtual::VirtualPromo()->page($options);


        Services::Helper()->showListTitle($list['data'], [], ['product_type' => 'system.prom_type']);
        return $list;
    }

    /**
     * 虚码规则列表limit
     * @param array $where |条件
     * @param int $limit | 数量
     * @return array
     * @throws Exception
     * @throws DbException
     */
    public function getPromoList(array $where = [], $limit = 10): array
    {
        return ModelVirtual::VirtualPromo()->getPromoList($where, $limit);
    }

    /**
     * 虚码规则详情
     * @param array $options
     * @return array
     * @throws Exception
     */
    public function getPromoInfo(array $options): array
    {
        if (empty($options['field'])) {
            $options['field'] = 'id,mer_id,title,product_type,union_rule,option,salesman,limit_num,status,begin_time,end_time,memo';
        }
        $info = ModelVirtual::VirtualPromo()->find($options);
        if (empty($info)) {
            api_exception(400, '虚码活动不存在或已删除');
        }
        return $info;
    }

    /**
     * 虚码规则编辑
     * @param array $params
     * @return int|mixed|string
     * @throws Exception
     */
    public function savePromo(array $params)
    {
        $id = $params['id'] ?? 0;
        unset($params['id'], $params['status']);
        if (!empty($params['product_type']) && $params['product_type'] == 2) {
            if (empty($params['union_rule'])) {
                api_exception(400, '活动联合规则不能为空');
            }
            if (empty($params['union_rule']['rule'])) {
                api_exception(400, '活动联合规则条件限制不能为空');
            }
            if ($params['union_rule']['rule'] == 2 && (empty($params['union_rule']['sum']) || $params['union_rule']['sum'] <= 0)) {
                api_exception(400, '活动联合规则数量限制不能小于0');
            }
        }
        if (!empty($params['product_type']) && $params['product_type'] == 1) {
            $params['union_rule'] = [
                'sum' => 0,
                'rule' => 0
            ];
        }

        $max_red_packet = ModelMerchant::MerchantInfo()->where('mer_id', $params['mer_id'])->value(null, 'max_red_packet');
        if (!empty($params['salesman'])) {
            //红包不可以大于最大数
            if (!empty($params['salesman']['red_packet']) && ($params['salesman']['red_packet'] < 0.3 || $params['salesman']['red_packet'] > $max_red_packet)) {
                api_exception(400, '导购红包不能小于0.3元或大于' . $max_red_packet . '元');
            }
            if (!empty($params['salesman']['point']) && $params['salesman']['point'] < 0.1) {
                api_exception(400, '导购积分不能小于0.1');
            }
            if (!empty($params['salesman']['day_num']) && $params['salesman']['day_num'] < 0) {
                api_exception(400, '导购日限制不能小于0');
            }
            if (empty($params['salesman']['red_packet']) && empty($params['salesman']['point'])) {
                api_exception(400, '导购积分红包两者必须开启一个');
            }
        }
        if (!empty($params['limit_num']) && $params['limit_num'] < 0) {
            api_exception(400, '活动总限制不能小于0');
        }
        $params['update_at'] = Dt()->format();
        if (!empty($id)) {
            ModelVirtual::VirtualPromo()->where('id', $id)->update([], $params);
        } else {
            $params['status'] = 0;
            $id = ModelVirtual::VirtualPromo()->insert($params, true);
        }
        return $id;
    }

    /**
     * 虚码规则编辑状态
     * @param array $where
     * @param array $update
     * @return int|mixed|string
     * @throws Exception
     */
    public function editPromoStatus(array $where, array $update)
    {
        try {
            $info = $this->getPromoInfo(['where' => $where]);
            $model = ModelVirtual::VirtualPromo();
            if (!empty($update['status'])) {
                $model_product = ModelVirtual::VirtualPromoProduct();
                $product_code = $model_product->where('vp_id', $info['id'])->where('mer_id', $info['mer_id'])->column([], 'product_code');
                if (empty($product_code)) {
                    api_exception(400, '请先添加活动商品');
                }
                if ($info['product_type'] == 1) {
                    $now = Dt()->format(2);
                    $vp_id = $model_product->removeOption()->where('vp_id', '<>', $info['id'])->where('mer_id', $info['mer_id'])->whereIn('product_code', $product_code)->column([], 'vp_id');
                    $count = empty($vp_id) ? 0 : $model->removeOption()->whereIn('id', $vp_id)->where('product_type', 1)->where('mer_id', $info['mer_id'])->where('status', 1)->where('begin_time', '<=', $now)->where('end_time', '>=', $now)->count('id');
                    if ($count > 0) {
                        api_exception(400, '活动商品在其他活动中存在');
                    }
                }
            }
            $model->removeOption()->where('id', $info['id'])->where('mer_id', $info['mer_id'])->update([], $update);
            return $info['id'];
        } catch (Exception $e) {
            throw $e;
        }
    }

    /**
     * 刷新活动状态，禁用已失效活动
     * @param $mer_id
     * @return int|string
     * @throws DbException
     */
    public function updatePromoAllStatus($mer_id)
    {
        $now = Dt()->format(2);
        return ModelVirtual::VirtualPromo()->where('mer_id', $mer_id)->where('status', 1)->where('end_time', '<', $now)->update([], ['status' => 0]);
    }

    /**
     * 虚码规则删除
     */
    public function delPromo(array $where): bool
    {
        try {
            if (empty($where)) {
                return false;
            }
            $model = ModelVirtual::VirtualPromo();
            $model->startTrans();
            $vpid = $model->where($where)->column([], 'id');
            if (!empty($vpid)) {
                $model->where($where)->delete();
                ModelVirtual::VirtualPromoProduct()->where('vp_id', 'in', $vpid)->delete();
                ModelVirtual::VirtualPromoSpecial()->where('vp_id', 'in', $vpid)->delete();
            }
            $model->commit();
        } catch (Exception $e) {
            $model->rollback();
            throw $e;
        }
        return true;
    }

    /**
     * 虚码活动商品列表
     */
    public function getPromoProductPage($options, $mer_id): array
    {
        if (empty($options['field'])) {
            $options['field'] = 'id,vp_id,mer_id,product_code,num';
        }
        $list = ModelVirtual::VirtualPromoProduct()->page($options);
        if (!empty($list['data'])) {
            $product_code = array_column($list['data'], 'product_code');
            $product = empty($product_code) ? [] : ModelMerchant::Product()->column(['mer_id' => ['=', $mer_id], 'code' => ['in', $product_code], 'delete_at' => ['=', null]], 'title', 'code');
            foreach ($list['data'] as &$v) {
                $v['product_code_tag'] = $product[$v['product_code']] ?? '';
            }
        }
        return $list;
    }

    /**
     * 编辑虚码活动商品
     */
    public function savePromoProduct($params): bool
    {
        try {
            $model = ModelVirtual::VirtualPromo();
            $modelPoduct = ModelVirtual::VirtualPromoProduct();
            $modelPoduct->startTrans();
            $vp = $model->where('id', $params['vp_id'])->field('id,mer_id,product_type,union_rule')->find();
            if (empty($vp)) {
                throw new Exception('虚码活动不存在');
            }
            $union_rule = $vp['union_rule'];
            $id = $params['id'] ?? 0;
            unset($params['id']);
            $now = Dt()->format(2);
            if (!empty($id)) {
                $params['update_at'] = $now;
                $modelPoduct->removeOption()->where('id', $id)->update([], $params);
            } else {
                $insert = $product_code = [];
                $promo_product = $modelPoduct->removeOption()->where('vp_id', $params['vp_id'])->where('mer_id', $vp['mer_id'])->column([], 'product_code');
                if ($vp['product_type'] == 1) {
                    $vpids = $model->removeOption()->where('product_type', 1)->where('mer_id', $vp['mer_id'])->where('status', 1)->where('begin_time', '<=', $now)->where('end_time', '>=', $now)->column([], 'id');
                    $product_code = empty($vpids) ? [] : $modelPoduct->removeOption()->whereIn('vp_id', $vpids)->where('mer_id', $vp['mer_id'])->column([], 'product_code');
                }
                $pro = $params['pro'] ?? [];
                if (empty($pro)) {
                    throw new Exception('虚码活动商品不能为空');
                }
                $pro_ids = array_column($pro, 'id');
                $product = ModelMerchant::Product()->whereIn('id', $pro_ids)->where('mer_id', $vp['mer_id'])->column([], 'code', 'id');
                if (empty($product)) {
                    throw new Exception('虚码活动商品不存在');
                }
                foreach ($pro as $v) {
                    if (empty($v['id']) || empty($product[$v['id']])) {
                        continue;
                    }
                    if (!empty($promo_product) && in_array($product[$v['id']], $promo_product, true)) {
                        continue;
                    }
                    if ($vp['product_type'] == 1 && in_array($product[$v['id']], $product_code, true)) {
                        continue;
                    }
                    if ($vp['product_type'] == 2 && $union_rule['rule'] == 2 && empty($v['num'])) {
                        throw new Exception('虚码活动商品数量不能为空');
                    }
                    $insert[] = [
                        'mer_id' => $params['mer_id'],        //
                        'vp_id' => $params['vp_id'],        // 虚码规则ID
                        'product_code' => $product[$v['id']],  // 商品code,
                        'num' => !empty($v['num']) ? $v['num'] : 1,// 商品数量,联合活动有效
                        'op_user' => $params['op_user'],  // 操作人
                        'create_at' => $now,        // 创建时间
                        'update_at' => $now,        // 更新时间
                    ];
                }

                if (!empty($insert)) {
                    $modelPoduct->removeOption()->insertAll($insert);
                    // 更新商品数量
                    ModelVirtual::VirtualPromo()->updateSpecialAndProductNum((int)$params['vp_id'], 2, 1, count($insert));
                }
            }
            $modelPoduct->commit();
        } catch (Exception $e) {
            $modelPoduct->rollback();
            throw $e;
        }
        return true;
    }

    /**
     * 删除虚码活动商品
     */
    public function delPromoProduct($where): int
    {
        if (empty($where)) {
            return 0;
        }
        $promoProductModel = ModelVirtual::VirtualPromoProduct();
        try {
            $promoProductModel->startTrans();
            $specInfo = $promoProductModel->where($where)->find();
            if (empty($specInfo)) {
                throw  new Exception(API_ERROR, '商品记录未找到');
            }
            $result = $promoProductModel->delete($where);
            ModelVirtual::VirtualPromo()->updateSpecialAndProductNum((int)$specInfo['vp_id'], 2, 0);
            $promoProductModel->commit();
            return $result;
        } catch (Exception $e) {
            $promoProductModel->rollback();
            throw  $e;
        }
    }

    /**
     * 虚码活动规则列表
     */
    public function getPromoSpecialPage($options): array
    {
        if (empty($options['field'])) {
            $options['field'] = 'id,vp_id,type,limit_way,small_ticket,red_packet,point,status,small_ticket';
        }
        $options['order'] = 'create_at desc';
        $list = ModelVirtual::VirtualPromoSpecial()->page($options);
        if (!empty($list['data'])) {
            Services::Helper()->showListTitle($list['data'], ['promo' => 'vp_id'], ['type' => 'system.special_type']);
        }
        return $list;
    }

    /**
     * 编辑虚码活动规则
     */
    public function savePromoSpecial($params)
    {
        $virtualPromoModel = ModelVirtual::VirtualPromo();
        $vp = $virtualPromoModel->where('id', $params['vp_id'])->where('mer_id', $params['mer_id'])->field('id,product_type,union_rule')->find();
        if (empty($vp)) {
            api_exception(400, '虚码活动不存在');
        }
        $id = $params['id'] ?? 0;
        unset($params['id']);
        $promoSpecialModel = ModelVirtual::VirtualPromoSpecial();
        $existTitle = $promoSpecialModel->getExistLimitWayTitle((int)$params['vp_id'], (int)$params['type'], $params['limit_way'], (int)$id);
        if ($existTitle !== '') {
            $specialType = config('system.special_type', []);
            api_exception(API_ERROR, sprintf("(%s) 在 下限制类型:(%s) 下已经使用,无法重复使用.", $existTitle, $specialType[$params['type']] ?? '未知'));
        }

        $limit_way = $this->getPromoSpecialType($params);
        if (empty($limit_way)) {
            api_exception(400, '规则限制内容不能为空');
        }
        if (!empty($params['red_packet']) && $params['red_packet'] < 0.3) {
            api_exception(400, '导购红包不能小于0.3元');
        }
        if (!empty($params['point']) && $params['point'] < 0) {
            api_exception(400, '导购积分不能小于0');
        }
        $params['limit_way'] = $limit_way;
        $params['update_at'] = Dt()->format();
        if (!empty($id)) {
            $promoSpecialModel->where('id', $id)->update([], $params);
        } else {
            try {
                $promoSpecialModel->startTrans();
                $id = $promoSpecialModel->insert($params, true);
                $virtualPromoModel->updateSpecialAndProductNum((int)$params['vp_id'], 1);
                $promoSpecialModel->commit();
            } catch (Exception $e) {
                $promoSpecialModel->rollback();
                throw  $e;
            }
        }
        return $id;
    }

    /**
     * 删除虚码活动规则
     */
    public function delPromoSpecial($where): int
    {
        if (empty($where)) {
            return 0;
        }
        $promoSpecialModel = ModelVirtual::VirtualPromoSpecial();
        try {
            $promoSpecialModel->startTrans();
            $specInfo = $promoSpecialModel->where($where)->find();
            if (empty($specInfo)) {
                throw  new Exception(API_ERROR, '规格记录未找到');
            }
            $result = $promoSpecialModel->delete($where);
            ModelVirtual::VirtualPromo()->updateSpecialAndProductNum((int)$specInfo['vp_id'], 1, 0);
            $promoSpecialModel->commit();
            return $result;
        } catch (Exception $e) {
            $promoSpecialModel->rollback();
            throw  $e;
        }

    }

    /**
     * 虚码活动规则详情
     */
    public function getPromoSpecialInfo($options)
    {
        if (empty($options['field'])) {
            $options['field'] = 'id,vp_id,type,limit_way,small_ticket,red_packet,point,status,small_ticket';
        }
        $info = ModelVirtual::VirtualPromoSpecial()->find($options);
        if (empty($info)) {
            api_exception(400, '活动规则不存在或已删除');
        }
        Services::Helper()->showInfoTitle($info, ['promo' => 'vp_id']);
        return $info;
    }

    /**
     * 编辑虚码活动规则状态
     */
    public function editSpecialStatus(array $where, array $update)
    {
        $info = $this->getPromoSpecialInfo(['where' => $where]);
        ModelVirtual::VirtualPromoSpecial()->removeOption()->update($where, $update);
        return $info['id'];
    }

    /**
     * 处理特殊规则列表
     */
    private function getPromoSpecialType($params)
    {
        $limit_way = [];
        switch ($params['type'] ?? 0) {
            case 1:
                if (!empty($params['limit_way'])) {
                    $limit_way = ModelShop::ShopTags()->whereIn('id', $params['limit_way'])->where('mer_id', $params['mer_id'])->column(null, 'id,title');
                }
                break;
            case 2:
                if (!empty($params['limit_way'])) {
                    $limit_way = ModelShop::Shop()->whereIn('id', $params['limit_way'])->where('mer_id', $params['mer_id'])->column(null, 'id,title');
                }
                break;
            case 3:
                if (!empty($params['limit_way'])) {
                    $limit_way = ModelShop::ShopSalesman()->whereIn('id', $params['limit_way'])->where('mer_id', $params['mer_id'])->column(null, 'id,name as title');
                }
                break;
        }
        return $limit_way;
    }

    /**
     * 展示商品已参加的活动，并判断是否可参加其他活动
     * @param array $list
     * @param string $mer_id
     * @param int $vp_id
     * @return mixed
     * @throws Exception
     */
    public function showVirtualPromo(array $list, string $mer_id, int $vp_id = 0)
    {
        $promo_product_list = [];
        if (!empty($list)) {
            $product_code = array_column($list, 'code');
            $promo_product = ModelVirtual::VirtualPromoProduct()->where('mer_id', $mer_id)->whereIn('product_code', $product_code)->field('vp_id,product_code')->select();
            $vp_ids = array_column($promo_product, 'vp_id');
            $vp_ids[] = $vp_id;
            $promo_list = ModelVirtual::VirtualPromo()->where('mer_id', $mer_id)->whereIn('id', $vp_ids)->column([], 'id,title,product_type,status', 'id');
            foreach ($promo_product as $v) {
                $promo = $promo_list[$v['vp_id']] ?? [];
                if (empty($promo)) {
                    continue;
                }
                $promo_product_list[$v['product_code']]['promo'][] = $promo;
                if (!empty($vp_id) && !empty($promo_list[$vp_id])) {
                    if ($promo['id'] == $vp_id) {
                        $promo_product_list[$v['product_code']]['promo_status'] = 2;
                    } elseif ($promo_list[$vp_id]['product_type'] == 1 && $promo['product_type'] == 1 && $promo['status'] == 1) {
                        $promo_product_list[$v['product_code']]['promo_status'] = 1;
                    }
                }
            }
        }
        foreach ($list as &$v) {
            $promo_product_info = $promo_product_list[$v['code']] ?? [];
            $v['promo'] = $promo_product_info['promo'] ?? [];
            $v['promo_status'] = $promo_product_info['promo_status'] ?? 0;
        }
        return $list;
    }
}
